/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>
#include <memory>
#include <thread>
#include <mutex>
#include <vector>
#include <atomic>
#include <chrono>
#include <dlfcn.h>
#include <test_utilities/test_base.h>
#include <mc/log.h>
#include <devmon/driver_abi.h>

#include "../../../drivers/accessor/accessor/accessor.h"
#include "../test_utils/root_object.h"

using namespace dev;
using namespace devmon;

namespace drivers {
namespace accessor {
namespace test {

// 模拟Chip接口 - 参照gen::Chip和Interface_Chip的实现方式
class mock_chip_interface : public mc::engine::interface<mock_chip_interface> {
public:
    MC_INTERFACE("org.test.MockChipInterface")

    // 定义属性，用于存储最后的写入数据
    mc::engine::property<uint32_t> last_write_offset;
    mc::engine::property<std::vector<uint8_t>> last_write_data;
    
    mock_chip_interface() {
        last_write_offset = 0;
        last_write_data = std::vector<uint8_t>();
    }

    // 直接在接口中实现BlockIO方法 - 参照Interface_Chip的实现
    std::vector<uint8_t> BlockIORead(const uint32_t& offset, const uint32_t& length) {
        // 模拟读取失败的情况
        if (offset == 0xDEAD) {
            MC_THROW(mc::system_exception, "Read failed");
        }
        
        // 返回测试数据：根据offset生成不同的数据
        std::vector<uint8_t> data;
        for (uint32_t i = 0; i < length; ++i) {
            data.push_back(static_cast<uint8_t>((offset + i) & 0xFF));
        }
        return data;
    }

    void BlockIOWrite(const uint32_t& offset, const std::vector<uint8_t>& buffer) {
        // 模拟写入失败的情况
        if (offset == 0xBEEF) {
            MC_THROW(mc::system_exception, "Write failed");
        }
        
        // 保存写入的数据用于验证
        last_write_offset = offset;
        last_write_data = buffer;
    }
};

// 模拟Chip对象
class mock_chip : public mc::engine::object<mock_chip> {
public:
    MC_OBJECT(mock_chip, "MockChip", "/bmc/topology/MockChip", (mock_chip_interface))
    
    mock_chip_interface m_interface;
    
    mock_chip() = default;
    ~mock_chip() = default;
     
    // 获取最后写入的数据用于测试验证
    uint32_t get_last_write_offset() const { return m_interface.last_write_offset.value(); }
    const std::vector<uint8_t>& get_last_write_data() const { return m_interface.last_write_data.value(); }
};

// 模拟异常Chip接口 - 总是抛出异常
class exception_mock_chip_interface : public mc::engine::interface<exception_mock_chip_interface> {
public:
    MC_INTERFACE("org.test.ExceptionMockChipInterface")

    // 定义属性，用于存储最后的写入数据
    mc::engine::property<uint32_t> last_write_offset;
    mc::engine::property<std::vector<uint8_t>> last_write_data;
    
    exception_mock_chip_interface() {
        last_write_offset = 0;
        last_write_data = std::vector<uint8_t>();
    }

    // 直接在接口中实现BlockIO方法 - 总是抛出异常
    std::vector<uint8_t> BlockIORead(const uint32_t& offset, const uint32_t& length) {
        MC_THROW(mc::system_exception, "Simulated read exception");
    }

    void BlockIOWrite(const uint32_t& offset, const std::vector<uint8_t>& buffer) {
        MC_THROW(mc::system_exception, "Simulated write exception");
    }
};

// 创建一个会抛出异常的mock chip
class exception_mock_chip : public mc::engine::object<exception_mock_chip> {
public:
    MC_OBJECT(exception_mock_chip, "ExceptionMockChip", "/bmc/topology/ExceptionMockChip", (exception_mock_chip_interface))
    
    exception_mock_chip_interface m_interface;
    
    exception_mock_chip() = default;
    ~exception_mock_chip() = default;
};

class accessor_test_service : public mc::engine::service {
public:
    accessor_test_service(const std::string& name) : mc::engine::service(name) {
    }
};

class AccessorTest : public mc::test::TestWithEngine {
protected:
    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
        m_test_service = mc::make_shared<accessor_test_service>("bmc.kepler.test_accessor");
        m_test_service->init();
        m_test_service->start();

        // 创建根对象
        m_root_object = root_object::create_root_object(m_test_service.get());
    }

    static void TearDownTestSuite() {
        m_test_service->stop();
        m_root_object.reset();
        m_test_service.reset();
        TestWithEngine::TearDownTestSuite();
    }

    void SetUp() override {
        // 创建模拟的Chip对象 - 使用position模式
        mc::mutable_dict functions;
        m_mock_chip = mock_chip::create();
        m_mock_chip->set_position("97");
        m_mock_chip->set_object_name("MockChip_97");
        m_test_service->register_object(m_mock_chip);
        
        // 创建Accessor对象
        m_accessor = mc::make_shared<Accessor>();
        m_accessor->set_position("97");
        m_accessor->set_object_name("Accessor");
        m_test_service->register_object(m_accessor);

        m_exception_chip = exception_mock_chip::create();
        m_exception_chip->set_position("97");  // 使用不同的position避免冲突
        m_exception_chip->set_object_name("ExceptionMockChip");
        m_test_service->register_object(m_exception_chip);
        
        // 保存chip名称用于引用
        m_chip_name = std::string(m_mock_chip->get_object_name());
        
        // 创建std::shared_ptr来管理服务，用于func_collection
        std::shared_ptr<mc::engine::service> service_ptr(m_test_service.get(), [](mc::engine::service*){});
        func_collection::get_instance().add("97", service_ptr, functions);
    }
    
    void TearDown() override {
        if (m_accessor) {
            m_test_service->unregister_object(std::string(m_accessor->get_object_path()));
            m_accessor.reset();
        }
        if (m_mock_chip) {
            m_test_service->unregister_object(std::string(m_mock_chip->get_object_path()));
            m_mock_chip.reset();
        }
        if (m_exception_chip) {
            m_test_service->unregister_object(std::string(m_exception_chip->get_object_path()));
            m_exception_chip.reset();
        }
    }
    
    // 创建测试用的CSR配置
    mc::mutable_dict create_test_csr() {
        mc::mutable_dict csr;
        csr["Chip"] = "#/" + m_chip_name.substr(0, m_chip_name.find("_"));  // 使用对象名作为引用
        csr["Offset"] = static_cast<uint32_t>(0x100);
        csr["Size"] = static_cast<uint8_t>(4);
        csr["Mask"] = static_cast<uint32_t>(0xFFFFFFFF);
        csr["Type"] = static_cast<uint8_t>(1);
        // 注意：不包含Value字段，因为它有自定义的getter/setter逻辑
        return csr;
    }
    
    mc::dict create_test_connector() {
        mc::dict connector{{"SystemId", 1}, {"Position", 1}, {"Slot", 1}};
        return connector;
    }
    
    // 辅助函数：设置Chip对象引用
    void set_chip_reference() {
        // 设置引用路径，格式为 #/ + 对象名
        std::string chip_ref_path = "#/" +  m_chip_name.substr(0, m_chip_name.find("_"));
        mc::variant ref_obj{chip_ref_path};
        from_variant(ref_obj, m_accessor->i_accessor.Chip);
    }

protected:
    static mc::shared_ptr<accessor_test_service> m_test_service;
    static root_object_ptr m_root_object;
    mc::shared_ptr<mock_chip> m_mock_chip;
    mc::shared_ptr<Accessor> m_accessor;
    mc::shared_ptr<exception_mock_chip> m_exception_chip;
    std::string m_chip_name;
};

mc::shared_ptr<accessor_test_service> AccessorTest::m_test_service;
root_object_ptr AccessorTest::m_root_object;

// 测试基本初始化
TEST_F(AccessorTest, test_basic_init) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    
    bool result = m_accessor->init(csr, connector);
    EXPECT_TRUE(result);
    
    // 验证属性是否正确设置
    EXPECT_EQ(m_accessor->i_accessor.Offset.get_value(), 0x100);
    EXPECT_EQ(m_accessor->i_accessor.Size.get_value(), 4);
    EXPECT_EQ(m_accessor->i_accessor.Mask.get_value(), 0xFFFFFFFF);
    EXPECT_EQ(m_accessor->i_accessor.Type.get_value(), 1);
}

// 测试Value属性的读取功能
TEST_F(AccessorTest, test_value_read) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    
    // 初始化Accessor
    bool result = m_accessor->init(csr, connector);
    ASSERT_TRUE(result);
    
    // 设置Chip对象引用
    set_chip_reference();
    
    // 读取Value，应该触发BlockIORead调用
    uint64_t value = m_accessor->i_accessor.Value.get_value().as<uint64_t>();
    
    // 验证读取的值：mock_chip返回的数据是根据offset生成的
    // offset=0x100, size=4, 预期数据为 [0x00, 0x01, 0x02, 0x03]
    // 转换为小端序uint64_t: 0x03020100
    EXPECT_EQ(value, 0x03020100ULL);
}

// 测试Value属性的写入功能
TEST_F(AccessorTest, test_value_write) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    
    // 初始化Accessor
    bool result = m_accessor->init(csr, connector);
    ASSERT_TRUE(result);
    
    // 设置Chip对象引用
    set_chip_reference();
    
    // 写入Value，应该触发BlockIOWrite调用
    uint64_t test_value = 0x12345678ULL;
    m_accessor->i_accessor.Value.set_value(test_value);
    
    // 验证写入的数据
    EXPECT_EQ(m_mock_chip->get_last_write_offset(), 0x100);
    
    const auto& write_data = m_mock_chip->get_last_write_data();
    EXPECT_EQ(write_data.size(), 4);
    
    // 验证小端序转换：0x12345678 -> [0x78, 0x56, 0x34, 0x12]
    EXPECT_EQ(write_data[0], 0x78);
    EXPECT_EQ(write_data[1], 0x56);
    EXPECT_EQ(write_data[2], 0x34);
    EXPECT_EQ(write_data[3], 0x12);
}

// 测试读取失败的情况
TEST_F(AccessorTest, test_read_failure) {
    auto csr = create_test_csr();
    csr["Offset"] = static_cast<uint32_t>(0xDEAD);  // 特殊值触发读取失败
    auto connector = create_test_connector();
    
    bool result = m_accessor->init(csr, connector);
    ASSERT_TRUE(result);
    
    set_chip_reference();
    
    // 读取Value，应该抛出异常
    EXPECT_THROW({
        uint64_t value = m_accessor->i_accessor.Value.get_value().as<uint64_t>();
    }, mc::invalid_op_exception);
}

// 测试写入失败的情况
TEST_F(AccessorTest, test_write_failure) {
    auto csr = create_test_csr();
    csr["Offset"] = static_cast<uint32_t>(0xBEEF);  // 特殊值触发写入失败
    auto connector = create_test_connector();
    
    bool result = m_accessor->init(csr, connector);
    ASSERT_TRUE(result);
    
    set_chip_reference();
    
    // 尝试写入Value，应该失败但不抛出异常
    uint64_t test_value = 0x12345678ULL;
    EXPECT_NO_THROW(m_accessor->i_accessor.Value.set_value(test_value));
}

// 测试无效Chip引用的情况
TEST_F(AccessorTest, test_invalid_chip_ref) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    
    bool result = m_accessor->init(csr, connector);
    ASSERT_TRUE(result);
    
    // 设置为无效的Chip引用 - 使用from_variant函数
    mc::variant ref_obj{std::string("#/InvalidChip")};
    from_variant(ref_obj, m_accessor->i_accessor.Chip);
    
    // 读取Value，应该抛出异常
    EXPECT_THROW({
        uint64_t value = m_accessor->i_accessor.Value.get_value().as<uint64_t>();
    }, mc::invalid_op_exception);
}

// 测试边界条件：Size为0的情况
TEST_F(AccessorTest, test_size_zero) {
    auto csr = create_test_csr();
    csr["Size"] = static_cast<uint8_t>(0);
    auto connector = create_test_connector();
    
    bool result = m_accessor->init(csr, connector);
    ASSERT_TRUE(result);
    
    set_chip_reference();
    
    // 读取Value，应该抛出异常（因为Size为0导致读取数据为空）
    EXPECT_THROW({
        uint64_t value = m_accessor->i_accessor.Value.get_value().as<uint64_t>();
    }, mc::invalid_op_exception);
    
    // 写入Value，应该成功但写入0字节
    uint64_t test_value = 0x12345678ULL;
    m_accessor->i_accessor.Value.set_value(test_value);
    
    const auto& write_data = m_mock_chip->get_last_write_data();
    EXPECT_EQ(write_data.size(), 0);
}

// 测试异常处理：Chip对象抛出异常
TEST_F(AccessorTest, test_chip_exception) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    
    bool result = m_accessor->init(csr, connector);
    ASSERT_TRUE(result);
    
    // 设置异常Chip对象引用 - 使用from_variant函数
    std::string exception_chip_name = std::string(m_exception_chip->get_object_name());
    mc::variant ref_obj{std::string("#/" + exception_chip_name)};
    from_variant(ref_obj, m_accessor->i_accessor.Chip);
    
    // 读取Value，应该抛出异常
    EXPECT_THROW({
        uint64_t value = m_accessor->i_accessor.Value.get_value().as<uint64_t>();
    }, mc::invalid_op_exception);
    
    // 写入Value，应该失败但不抛出异常
    uint64_t test_value = 0x12345678ULL;
    EXPECT_NO_THROW(m_accessor->i_accessor.Value.set_value(test_value));
}

// 测试大数据量：Size为8字节的情况
TEST_F(AccessorTest, test_large_data) {
    auto csr = create_test_csr();
    csr["Size"] = static_cast<uint8_t>(8);
    csr["Offset"] = static_cast<uint32_t>(0x300);
    auto connector = create_test_connector();
    
    bool result = m_accessor->init(csr, connector);
    ASSERT_TRUE(result);
    
    set_chip_reference();
    
    // 读取Value
    uint64_t value = m_accessor->i_accessor.Value.get_value().as<uint64_t>();
    
    // 验证8字节数据：offset=0x300, 预期数据为 [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
    // 转换为小端序uint64_t: 0x0706050403020100
    EXPECT_EQ(value, 0x0706050403020100ULL);
    
    // 测试写入大数据
    uint64_t test_value = 0x123456789ABCDEF0ULL;
    m_accessor->i_accessor.Value.set_value(test_value);
    
    const auto& write_data = m_mock_chip->get_last_write_data();
    EXPECT_EQ(write_data.size(), 8);
    
    // 验证小端序转换
    EXPECT_EQ(write_data[0], 0xF0);
    EXPECT_EQ(write_data[1], 0xDE);
    EXPECT_EQ(write_data[2], 0xBC);
    EXPECT_EQ(write_data[3], 0x9A);
    EXPECT_EQ(write_data[4], 0x78);
    EXPECT_EQ(write_data[5], 0x56);
    EXPECT_EQ(write_data[6], 0x34);
    EXPECT_EQ(write_data[7], 0x12);
}

// 测试并发访问：多个线程同时读写Value属性
TEST_F(AccessorTest, test_concurrent_access) {
    auto csr = create_test_csr();
    auto connector = create_test_connector();
    
    bool result = m_accessor->init(csr, connector);
    ASSERT_TRUE(result);
    
    set_chip_reference();
    
    // 创建多个线程同时访问Value属性
    std::vector<std::thread> threads;
    std::vector<uint64_t> read_values;
    std::mutex read_mutex;
    std::atomic<bool> all_threads_ready{false};
    std::atomic<int> ready_count{0};
    const int total_threads = 8;
    
    // 启动多个读取线程
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back([this, &read_values, &read_mutex, &all_threads_ready, &ready_count, total_threads]() {
            // 等待所有线程准备就绪
            ready_count++;
            while (!all_threads_ready.load() && ready_count.load() < total_threads) {
                std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
            
            try {
                uint64_t value = m_accessor->i_accessor.Value.get_value().as<uint64_t>();
                std::lock_guard<std::mutex> lock(read_mutex);
                read_values.push_back(value);
            } catch (const std::exception& e) {
                // 并发测试中可能出现异常，记录但不失败
                std::lock_guard<std::mutex> lock(read_mutex);
                read_values.push_back(0xDEADBEEF);  // 标记异常情况
            }
        });
    }
    
    // 启动多个写入线程
    for (int i = 0; i < 3; ++i) {
        threads.emplace_back([this, i, &all_threads_ready, &ready_count, total_threads]() {
            // 等待所有线程准备就绪
            ready_count++;
            while (!all_threads_ready.load() && ready_count.load() < total_threads) {
                std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
            
            try {
                uint64_t test_value = 0x10000000ULL * (i + 1);
                m_accessor->i_accessor.Value.set_value(test_value);
            } catch (const std::exception& e) {
                // 并发测试中写入可能失败，这是可以接受的
            }
        });
    }
    
    // 等待所有线程准备就绪后开始测试
    while (ready_count.load() < total_threads) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
    all_threads_ready.store(true);
    
    // 等待所有线程完成
    for (auto& thread : threads) {
        thread.join();
    }
    
    // 验证至少有一些成功的读取操作
    int successful_reads = 0;
    for (uint64_t value : read_values) {
        if (value != 0xDEADBEEF) {
            successful_reads++;
        }
    }
    
    // 至少应该有一半的读取操作成功
    EXPECT_GT(successful_reads, 0);
    EXPECT_EQ(read_values.size(), 5);  // 应该有5个读取线程的结果
}

} // namespace test
} // namespace accessor
} // namespace drivers

// 为mock类添加反射支持
MC_REFLECT(drivers::accessor::test::mock_chip_interface, 
    ((last_write_offset, "LastWriteOffset"))
    ((last_write_data, "LastWriteData"))
    ((BlockIORead, "BlockIORead"))
    ((BlockIOWrite, "BlockIOWrite")))
MC_REFLECT(drivers::accessor::test::mock_chip, ((m_interface, "interface")))
MC_REFLECT(drivers::accessor::test::exception_mock_chip_interface, 
    ((last_write_offset, "LastWriteOffset"))
    ((last_write_data, "LastWriteData"))
    ((BlockIORead, "BlockIORead"))
    ((BlockIOWrite, "BlockIOWrite")))
MC_REFLECT(drivers::accessor::test::exception_mock_chip, ((m_interface, "interface"))) 